/*
 * GameMap.java
 * 
 * author: The MomberBan Team
 *    date: 12.09.2008
 * 
 * 
 */

package at.momberban.game.me;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.Hashtable;

import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.TiledLayer;

/**
 * parse all available maps for momberban
 * 
 * @author patchinsky
 */
public class GameMap {
    private static final String TOKEN_SIZE = "size";

    private static final String TOKEN_TITLE = "title";

    private static final String TOKEN_PLAYERS = "players";

    private static final String TOKEN_MAP = "map";

    private static final char FREE_SPACE = '.';

    private static final char WALL_UNBREAKABLE = 'u';

    private static final char WALL_BREAKABLE = 'b';

    private static final String PATH_FREESPACE = "/Background.png";

    private static final String PATH_UNBREAKABLE = "/Wall.png";

    private static final String PATH_BREAKABLE = "/Block.png";

    private static Image IMAGE_FREESPACE;

    private static Image IMAGE_UNBREAKABLE;

    private static Image IMAGE_BREAKABLE;

    private static GameMap[] maps;

    private int playerSpeed;

    private int maxPlayers;

    private int defaultMaxPlayers;

    private String fileName;

    private int width;

    private int height;

    private String title;

    private TiledLayer backgroundLayer;

    private TiledLayer breakableLayer;

    private TiledLayer unbreakableLayer;

    private int row;

    private Hashtable spawns;

    private int xTiles;

    private int yTiles;

    /**
     * load all maps
     */
    static {
        try {
            IMAGE_UNBREAKABLE = Image.createImage(PATH_UNBREAKABLE);
            IMAGE_BREAKABLE = Image.createImage(PATH_BREAKABLE);
            IMAGE_FREESPACE = Image.createImage(PATH_FREESPACE);
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        /*
         * File f = new File(); System.out.println(File.getStorageRoot());
         * Vector dir = f.filenamesThatStartWith("Map"); for (int i = 0; i <
         * dir.size(); i++) { System.out.println(dir.elementAt(i)); }
         * dir.copyInto(GameMap.cache);
         */

        GameMap.maps = new GameMap[] { new GameMap("/MapClassic4P.txt") };
    }

    /**
     * constructor
     * 
     * @param name
     *            the resource to load
     */
    public GameMap(String name) {
        this.fileName = name;
        this.title = this.fileName;
    }

    /**
     * read the map
     * 
     * @throws IOException
     */
    public void readMap() throws IOException {
        this.spawns = new Hashtable();

        Logger.log("loading map: " + this.fileName);

        DataInputStream in = new DataInputStream(MomberBanMidlet.class
                .getResourceAsStream(this.fileName));

        StringBuffer str = new StringBuffer();

        byte[] b = new byte[1];
        int i = 1;
        String[] buffer = new String[1];
        this.row = 0;

        // read the whole map file
        while (in.read(b) != -1) {
            switch ((char) b[0]) {
                case ' ':
                case '\r':
                case '\n':
                    if (str.length() > 0) {
                        parse(str.toString(), buffer, i);
                        str.setLength(0);

                        // for parsing the assignment (0 left part, 1 assign, 2
                        // right part)
                        i++;
                        if (i > 3) {
                            i = 1;
                        }
                    }

                    break;
                default:
                    str.append((char) b[0]);
            }
        }
        in.close();

        if (this.backgroundLayer != null) {
            this.width = this.backgroundLayer.getWidth();
            this.height = this.backgroundLayer.getHeight();
        }

        Logger.log("title: " + this.title);
        Logger.log("metrics: " + this.width + "x" + this.height);
        Logger.log("maximum players: " + this.maxPlayers);
    }

    /**
     * return the maps
     * 
     * @return maps
     */
    public static GameMap[] getMaps() {
        return maps;
    }

    /**
     * @return title
     */
    public String getTitle() {
        return title;
    }

    /**
     * parse the input data
     * 
     * @param data
     */
    private void parse(String token, String[] buffer, int i) {
        // if in map mode
        if (buffer[0] != null && buffer[0].equals(TOKEN_MAP)) {
            for (int j = 0; j < this.xTiles; j++) {
                switch (token.charAt(j)) {
                    case WALL_BREAKABLE:
                        breakableLayer.setCell(j, this.row, 1);
                        unbreakableLayer.setCell(j, this.row, 0);
                        break;
                    case WALL_UNBREAKABLE:
                        breakableLayer.setCell(j, this.row, 0);
                        unbreakableLayer.setCell(j, this.row, 1);
                        break;
                    case FREE_SPACE:
                        breakableLayer.setCell(j, this.row, 0);
                        unbreakableLayer.setCell(j, this.row, 0);
                        break;
                    default:
                        Integer playerId = IntegerCache.valueOf(StringUtilities
                                .getNumericValue(token.charAt(j)));
                        int[] pos = new int[2];
                        pos[0] = j * IMAGE_FREESPACE.getWidth();
                        pos[1] = row * IMAGE_FREESPACE.getHeight();

                        Logger.log("spawn: " + playerId + " at " + pos[0]
                                + ", " + pos[1]);

                        this.spawns.put(playerId, pos);
                }

                backgroundLayer.setCell(j, this.row, 1);
            }

            // next row
            this.row++;
        } else if (token.equals(TOKEN_MAP)) { // assign map mode for parsing
            buffer[0] = token;
        } else { // default settings parser
            switch (i) {
                case 1: // remember the left part
                    buffer[0] = token;
                    break;
                case 3: // right part
                    if (buffer[0].equals(TOKEN_SIZE)) {
                        // extract the amount of tiles (w,h)
                        this.xTiles = Integer.valueOf(
                                token.substring(0, token.indexOf("x")))
                                .intValue();
                        this.yTiles = Integer.valueOf(
                                token.substring(token.indexOf("x") + 1))
                                .intValue();

                        // create the layers
                        this.backgroundLayer = new TiledLayer(this.xTiles,
                                this.yTiles, IMAGE_FREESPACE, IMAGE_FREESPACE
                                        .getWidth(), IMAGE_FREESPACE
                                        .getHeight());

                        this.breakableLayer = new TiledLayer(this.xTiles,
                                this.yTiles, IMAGE_BREAKABLE, IMAGE_BREAKABLE
                                        .getWidth(), IMAGE_BREAKABLE
                                        .getHeight());

                        this.unbreakableLayer = new TiledLayer(this.xTiles,
                                this.yTiles, IMAGE_UNBREAKABLE,
                                IMAGE_UNBREAKABLE.getWidth(), IMAGE_UNBREAKABLE
                                        .getHeight());

                    } else if (buffer[0].equals(TOKEN_TITLE)) {
                        this.title = token;
                    } else if (buffer[0].equals(TOKEN_PLAYERS)) {
                        this.maxPlayers = Integer.valueOf(token).intValue();
                        this.defaultMaxPlayers = this.maxPlayers;
                    } else {
                        // unrecognized setting
                    }
                    break;
            }
        }

    }

    /**
     * Getter of the property <tt>maxPlayers</tt>
     * 
     * @return Returns the maxPlayers.
     */

    public int getMaxPlayers() {
        return maxPlayers;
    }

    /**
     * Setter of the property <tt>maxPlayers</tt>
     * 
     * @param maxPlayers
     *            The maxPlayers to set.
     */
    public void setMaxPlayers(int maxPlayers) {
        this.maxPlayers = maxPlayers;
    }

    /**
     * Getter of the property <tt>playerSpeed</tt>
     * 
     * @return Returns the playerSpeed.
     */

    public int getPlayerSpeed() {
        return playerSpeed;
    }

    /**
     * Setter of the property <tt>playerSpeed</tt>
     * 
     * @param playerSpeed
     *            The playerSpeed to set.
     */
    public void setPlayerSpeed(int playerSpeed) {
        this.playerSpeed = playerSpeed;
    }

    /**
     * @return backgroundLayer
     */
    public TiledLayer getBackgroundLayer() {
        return backgroundLayer;
    }

    /**
     * @return breakableLayer
     */
    public TiledLayer getBreakableLayer() {
        return breakableLayer;
    }

    /**
     * @return unbreakableLayer
     */
    public TiledLayer getUnbreakableLayer() {
        return unbreakableLayer;
    }

    /**
     * return the x spawn for a player
     * 
     * @param id
     * @return
     */
    public int getXSpawn(int id) {
        int pos[] = (int[]) this.spawns.get(IntegerCache.valueOf(id));
        return pos[0];
    }

    /**
     * return the y spawn for a player
     * 
     * @param id
     * @return
     */
    public int getYSpawn(int id) {
        int pos[] = (int[]) this.spawns.get(IntegerCache.valueOf(id));
        return pos[1];
    }

    /**
     * @return width
     */
    public int getWidth() {
        return width;
    }

    /**
     * @return height
     */
    public int getHeight() {
        return height;
    }

    /**
     * @return xTiles
     */
    public int getXTiles() {
        return xTiles;
    }

    /**
     * @return yTiles
     */
    public int getYTiles() {
        return yTiles;
    }

    /**
     * @return defaultMaxPlayers
     */
    public int getDefaultMaxPlayers() {
        return defaultMaxPlayers;
    }
}
